package frame

import (
	"encoding/binary"
	"errors"
	"io"
)

/*
Frame定义
	frameHeader + framePayload(packet)

	frameHeader
		4 bytes: length 整型，帧总长度(含头及payload)
	framePayload
		Packet
*/
type FramePayload []byte

/**
  stream 编解码器定义
*/
type StreamFrameCodec interface {

	// data -> frame，并写入io.Writer
	Encode(writer io.Writer, payload FramePayload) error

	// data -> frame，并写入io.Writer
	Decode(reader io.Reader) (FramePayload, error)
}

var ErrLessWritten = errors.New("less write")
var ErrLessRead = errors.New("less read")

type DefinedFrameCodec struct{}

// 创建一个实现编码器的对象
func NewFrameCodec() StreamFrameCodec {
	return &DefinedFrameCodec{}
}

// 实现 接口的encode方法
func (frame *DefinedFrameCodec) Encode(writer io.Writer, payload FramePayload) error {
	var f = payload

	// payload长度 + totalLength int32 的4个字节的长度
	var totalLen int32 = int32(len(payload)) + 4

	// 写入长度字段
	// 网络字节序使用大端字节序（BigEndian），因此无论是 Encode 还是 Decode，都是用 binary.BigEndian
	err := binary.Write(writer, binary.BigEndian, &totalLen)
	if err != nil {
		return err
	}

	// 写入数据长度
	written, err := writer.Write([]byte(f))
	if err != nil {
		return err
	}
	// 写入的数据丢失了
	if written != len(payload) {
		return ErrLessWritten
	}
	return nil
}

// 实现 接口的decode方法
func (frame *DefinedFrameCodec) Decode(reader io.Reader) (FramePayload, error) {

	var totalLen int32

	// 读取长度字段
	// 网络字节序使用大端字节序（BigEndian），因此无论是 Encode 还是 Decode，都是用 binary.BigEndian
	err := binary.Read(reader, binary.BigEndian, &totalLen)
	if err != nil {
		return nil, err
	}

	buf := make([]byte, totalLen-4)

	// io.ReadFull 一般会读满所需的字节数
	read, err := io.ReadFull(reader, buf)

	if err != nil {
		return nil, err
	}

	if read != int(totalLen-4) {
		return nil, ErrLessRead
	}
	return FramePayload(buf), nil
}
